home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / stdio / vfprintf.c.old < prev    next >
Text File  |  1989-08-06  |  21KB  |  917 lines

  1. /* 
  2.  * vfprintf.c --
  3.  *
  4.  *    Source code for the "vfprintf" library procedure.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfprintf.c,v 1.9 89/07/28 15:56:48 rab Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <varargs.h>
  25.  
  26. #ifndef TRUE
  27. #define TRUE 1
  28. #endif
  29. #ifndef FALSE
  30. #define FALSE 0
  31. #endif
  32.  
  33. /*
  34.  * The following defines the size of buffer needed to hold the ASCII
  35.  * digits for the largest floating-point number and the largest integer.
  36.  */
  37.  
  38. #define CVT_DBL_BUF_SIZE 320
  39. #define CVT_INT_BUF_SIZE 33
  40.  
  41. /*
  42.  *----------------------------------------------------------------------
  43.  *
  44.  * CvtUtoA --
  45.  *
  46.  *    Convert a number from internal form to a sequence of
  47.  *    ASCII digits.
  48.  *
  49.  * Results:
  50.  *    The return value is a pointer to the ASCII digits representing
  51.  *    i, and *lengthPtr will be filled in with the number of digits
  52.  *    stored at the location pointed to by the return value.  The
  53.  *    return value points somewhere inside buf, but not necessarily
  54.  *    to the beginning.  Note:  the digits are left null-terminated.
  55.  *
  56.  * Side effects:
  57.  *    None.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61.  
  62. static char *
  63. CvtUtoA(i, base, buf, lengthPtr)
  64.     register unsigned i;    /* Value to convert. */
  65.     register int base;        /* Base for conversion.  Shouldn't be
  66.                  * larger than 36.  2, 8, and 16
  67.                  * execute fastest.
  68.                  */
  69.     register char *buf;        /* Buffer to use to hold converted string.
  70.                  * Must hold at least CVT_INT_BUF_SIZE bytes. */
  71.     int *lengthPtr;        /* Number of digits is stored here. */
  72. {
  73.     register char *p;
  74.  
  75.     /*
  76.      * Handle a zero value specially.
  77.      */
  78.  
  79.     if (i == 0) {
  80.     buf[0] = '0';
  81.     buf[1] = 0;
  82.     *lengthPtr = 1;
  83.     return buf;
  84.     }
  85.  
  86.     /*
  87.      * Build the string backwards from the end of the result array.
  88.      */
  89.  
  90.     p = &buf[CVT_INT_BUF_SIZE-1];
  91.     *p = 0;
  92.  
  93.     switch (base) {
  94.  
  95.     case 2:
  96.         while (i != 0) {
  97.         p -= 1;
  98.         *p = '0' + (i & 01);
  99.         i >>= 1;
  100.         }
  101.         break;
  102.     
  103.     case 8:
  104.         while (i != 0) {
  105.         p -= 1;
  106.         *p = '0' + (i & 07);
  107.         i >>= 3;
  108.         }
  109.         break;
  110.     
  111.     case 16:
  112.         while (i !=0) {
  113.         p -= 1;
  114.         *p = '0' + (i & 0xf);
  115.         if (*p > '9') {
  116.             *p += 'a' - '9' - 1;
  117.         }
  118.         i >>= 4;
  119.         }
  120.         break;
  121.     
  122.     default:
  123.         while (i != 0) {
  124.         p -= 1;
  125.         *p = '0' + (i % base);
  126.         if (*p > '9') {
  127.             *p += 'a' - '9' - 1;
  128.         }
  129.         i /= base;
  130.         }
  131.         break;
  132.     }
  133.  
  134.     *lengthPtr = (&buf[CVT_INT_BUF_SIZE-1] - p);
  135.     return p;
  136. }
  137.  
  138. /*
  139.  *----------------------------------------------------------------------
  140.  *
  141.  * CvtFtoA --
  142.  *
  143.  *    This procedure converts a double-precision floating-point
  144.  *    number to a string of ASCII digits.
  145.  *
  146.  * Results:
  147.  *    The characters at buf are modified to hold up to numDigits ASCII
  148.  *    characters, followed by a null character.  The digits represent
  149.  *    the most significant numDigits digits of value, with the lowest
  150.  *    digit rounded.  The value at *pointPtr is modified to hold
  151.  *    the number of characters in buf that precede the decimal point.
  152.  *    A negative value of *pointPtr means zeroes must be inserted
  153.  *    between the point and buf[0].  If value is negative, *signPtr
  154.  *    is set to TRUE;    otherwise it is set to FALSE.  The return value
  155.  *    is the number of digits stored in buf, which is either:
  156.  *    (a) numDigits (if the number is so huge that all numDigits places are
  157.  *        used before getting to the right precision level, or if
  158.  *        afterPoint is -1)
  159.  *    (b) afterPoint + *pointPtr (the normal case if afterPoint isn't -1)
  160.  *    If there were no significant digits within the specified precision,
  161.  *    then *pointPtr gets set to -afterPoint and 0 is returned.
  162.  *
  163.  * Side effects:
  164.  *    None.
  165.  *
  166.  *----------------------------------------------------------------------
  167.  */
  168.  
  169. static int
  170. CvtFtoA(value, numDigits, afterPoint, pointPtr, signPtr, buf, fpError)
  171.     double value;        /* Value to be converted. */
  172.     int numDigits;        /* Maximum number of significant digits
  173.                  * to generate in result. */
  174.     int afterPoint;        /* Maximum number of digits to generate
  175.                  * after the decimal point.  If -1, then
  176.                  * there there is no limit. */
  177.     int *pointPtr;        /* Will be filled in with position of
  178.                  * decimal point (number of digits before
  179.                  * decimal point). */
  180.     int *signPtr;        /* Modified to indicate whether or not
  181.                  * value was negative. */
  182.     char *buf;            /* Place to store ASCII digits.  Must hold
  183.                  * at least numDigits+1 bytes. */
  184.     int *fpError;               /* pointer to flag that is set if the number
  185.                                    is not a valid number. */
  186.  
  187. {
  188.     extern double modf();
  189.     register char *p;
  190.     double fraction, intPart;
  191.     int i, numDigits2;
  192.     char tmpBuf[CVT_DBL_BUF_SIZE];
  193.                 /* Large enough to hold largest possible
  194.                  * floating-point number.
  195.                  */
  196.  
  197.     /*
  198.      * Make sure the value is a valid number
  199.      */
  200.     {
  201.     union {
  202.         double d;
  203.         long l[2];
  204.     } u;
  205.  
  206.     /*
  207.      * Put the value into a union so we can check out the bits.
  208.      */
  209.     u.d = value;
  210.  
  211.     /*
  212.      * An IEEE Std 754 double precision floating point number
  213.          * has the following format:
  214.      *
  215.      *      1  bit       -- sign of Mantissa
  216.      *      11 bits      -- exponent
  217.      *      52 bits      -- Mantissa
  218.      *
  219.      * If the exponent has all bits set, the value is not a 
  220.      * real number.
  221.      *
  222.      * If the Mantissa is zero then the value is infinity, which
  223.      * is the result of division by zero, or overflow.
  224.      *
  225.      * If the Mantissa is non-zero the value is not a number (NaN).
  226.      * NaN can be generated by dividing zero by itself, taking the
  227.      * logarithm of a negative number, etc.
  228.      */
  229.  
  230.     /*
  231.      * check the exponent
  232.      */
  233.     if ((u.l[0] & 0x7ff00000) == 0x7ff00000) {
  234.         /*
  235.          * Set the error flag so the invoking function will know
  236.          * that something is wrong.
  237.          */
  238.         *fpError = TRUE;
  239.  
  240.         /*
  241.          * See if the Mantissa is zero.
  242.          */
  243.         if ((u.l[0] & ~0xfff00000) == 0 && u.l[1] == 0) {
  244.         strcpy(buf, "(INFINITY)");
  245.         return sizeof("(INFINITY)") - 1;
  246.         } else {
  247.         strcpy(buf, "(NaN)");
  248.         return sizeof("(NaN)") - 1;
  249.         }
  250.     } else {
  251.         *fpError = FALSE;
  252.     }
  253.     }
  254.  
  255.     /*
  256.      * Take care of the sign.
  257.      */
  258.  
  259.     if (value < 0.0) {
  260.     *signPtr = TRUE;
  261.     value = -value;
  262.     } else {
  263.     *signPtr = FALSE;
  264.     }
  265.  
  266.     /*
  267.      * Divide value into an integer and a fractional component.  Convert
  268.      * the integer to ASCII in a temporary buffer, then move the characters
  269.      * to the real buffer (since we're converting from the bottom up,
  270.      * we won't know the highest-order digit until last).
  271.      */
  272.  
  273.     fraction = modf(value, &intPart);
  274.     *pointPtr = 0;
  275.     for (p = &tmpBuf[CVT_DBL_BUF_SIZE-1]; intPart != 0; p -= 1) {
  276.     double tmp;
  277.     char digit;
  278.  
  279.     tmp = modf(intPart/10.0, &intPart);
  280.  
  281.     digit = (tmp * 10.0) + .2;
  282.     *p = digit + '0';
  283.     *pointPtr += 1;
  284.     }
  285.     p++;
  286.     for (i = 0; (i <= numDigits) && (p <= &tmpBuf[CVT_DBL_BUF_SIZE-1]);
  287.         i++, p++) {
  288.     buf[i] = *p;
  289.     }
  290.  
  291.     /*
  292.      * If the value was zero, put an initial zero in the buffer
  293.      * before the decimal point.
  294.      */
  295.     
  296.     if (value == 0.0) {
  297.     buf[0] = '0';
  298.     i = 1;
  299.     *pointPtr = 1;
  300.     }
  301.  
  302.     /*
  303.      * Now handle the fractional part that's left.  Repeatedly multiply
  304.      * by 10 to get the next digit.  At the beginning, the value may be
  305.      * very small, so do repeated multiplications until we get to a
  306.      * significant digit.
  307.      */
  308.     
  309.     if ((i == 0) && (fraction > 0)) {
  310.     while (fraction < .1) {
  311.         fraction *= 10.0;
  312.         *pointPtr -= 1;
  313.     };
  314.     }
  315.  
  316.     /*
  317.      * Compute how many total digits we should generate, taking into
  318.      * account both numDigits and afterPoint.  Then generate the digits.
  319.      */
  320.     
  321.     numDigits2 = afterPoint + *pointPtr;
  322.     if ((afterPoint < 0) || (numDigits2 > numDigits)) {
  323.     numDigits2 = numDigits;
  324.     }
  325.     
  326.     for ( ; i <= numDigits2; i++) {
  327.     double tmp;
  328.     char digit;
  329.  
  330.     fraction = modf(fraction*10.0, &tmp);
  331.  
  332.     digit = tmp;
  333.     buf[i] = digit + '0';
  334.     }
  335.  
  336.     /*
  337.      * The code above actually computed one more digit than is really
  338.      * needed.  Use it to round the low-order significant digit, if
  339.      * necessary.  This could cause rounding to propagate all the way
  340.      * back through the number.
  341.      */
  342.     
  343.     if ((numDigits2 >= 0) && (buf[numDigits2] >= '5')) {
  344.     for (i = numDigits2-1; ; i--) {
  345.         if (i < 0) {
  346.         int j;
  347.  
  348.         /*
  349.          * Must slide the entire buffer down one slot to make
  350.          * room for a leading 1 in the buffer.  Careful: if we've
  351.          * already got numDigits digits, must drop the last one to
  352.          * add the 1.
  353.          */
  354.  
  355.         for (j = numDigits2; j > 0; j--) {
  356.             buf[j] = buf[j-1];
  357.         }
  358.         if (numDigits2 < numDigits) {
  359.             numDigits2++;
  360.         }
  361.         (*pointPtr)++;
  362.         buf[0] = '1';
  363.         break;
  364.         }
  365.  
  366.         buf[i] += 1;
  367.         if (buf[i] <= '9') {
  368.         break;
  369.         }
  370.         buf[i] = '0';
  371.     }
  372.     }
  373.  
  374.     if (numDigits2 <= 0) {
  375.     numDigits2 = 0;
  376.     *pointPtr = -afterPoint;
  377.     }
  378.     buf[numDigits2] = 0;
  379.     return numDigits2;
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * vfprintf --
  386.  *
  387.  *    This utility routine does all of the real work of printing
  388.  *    formatted information.  It is called by printf, fprintf,
  389.  *    sprintf, vprintf, and vsprintf.
  390.  *
  391.  * Results:
  392.  *    The return value is the total number of characters printed.
  393.  *
  394.  * Side effects:
  395.  *    Information is output on stream.  See the manual page entry
  396.  *    for printf for details.
  397.  *
  398.  *----------------------------------------------------------------------
  399.  */
  400.  
  401. int
  402. vfprintf(stream, format, args)
  403.     register FILE *stream;    /* Where to output formatted results. */
  404.     register char *format;    /* Contains literal text and format control
  405.                  * sequences indicating how args are to be
  406.                  * printed.  See the man page for details. */
  407.     va_list args;        /* Variable number of values to be formatted
  408.                  * and printed. */
  409. {
  410.     int leftAdjust;        /* TRUE means field should be left-adjusted. */
  411.     int minWidth;        /* Minimum width of field. */
  412.     int precision;        /* Precision for field (e.g. digits after
  413.                  * decimal, or string length). */
  414.     int altForm;        /* TRUE means value should be converted to
  415.                  * an alternate form (depends on type of
  416.                  * conversion). */
  417.     register char c;        /* Current character from format string.
  418.                  * Eventually it ends up holding the format
  419.                  * type (e.g. 'd' for decimal). */
  420.     char pad;            /* Pad character. */
  421.     char buf[CVT_DBL_BUF_SIZE+10];
  422.                 /* Buffer used to hold converted numbers
  423.                  * before outputting to stream.  Must be
  424.                  * large enough for floating-point number
  425.                  * plus sign plus "E+XXX + null" */
  426.     char expBuf[CVT_INT_BUF_SIZE];
  427.                 /* Buffer to use for converting exponents. */
  428.     char *prefix;        /* Holds non-numeric stuff that precedes
  429.                  * number, such as "-" or "0x".  This is
  430.                  * kept separate to be sure we add padding
  431.                  * zeroes AFTER the prefix. */
  432.     register char *field;    /* Pointer to converted field. */
  433.     int actualLength;        /* Actual length of converted field. */
  434.     int point;            /* Location of decimal point, for "f" and
  435.                  * "e" conversions. */
  436.     int sign;            /* Also used for "f" and "e" conversions. */
  437.     int i, tmp;
  438.     int charsPrinted = 0;    /* Total number of characters output. */
  439.     char *end;
  440.     int fpError = FALSE;
  441.  
  442.     /*
  443.      * The main loop is to scan through the characters in format.
  444.      * Anything but a '%' is output directly to stream.  A '%'
  445.      * signals the start of a format field;  the formatting information
  446.      * is parsed, the next value from args is formatted and printed,
  447.      * and the loop goes on.
  448.      */
  449.  
  450.     for (c = *format; c != 0; format++, c = *format) {
  451.  
  452.     if (c != '%') {
  453.         putc(c, stream);
  454.         charsPrinted += 1;
  455.         continue;
  456.     }
  457.  
  458.     /*
  459.      * Parse off the format control fields.
  460.      */
  461.  
  462.     leftAdjust    = FALSE;
  463.     pad        = ' ';
  464.     minWidth    = 0;
  465.     precision    = -1;
  466.     altForm        = FALSE;
  467.     prefix        = "";
  468.     actualLength = 0;
  469.  
  470.     format++;  
  471.     c = *format;
  472.     while (TRUE) {
  473.         if (c == '-') {
  474.         leftAdjust = TRUE;
  475.         } else if (c == '0') {
  476.         pad = '0';
  477.         } else if (c == '#') {
  478.         altForm = TRUE;
  479.         } else if (c == '+') {
  480.         prefix = "+";
  481.         actualLength = 1;
  482.         } else {
  483.         break;
  484.         }
  485.         format++;
  486.         c = *format;
  487.     }
  488.     if (isdigit(c)) {
  489.         minWidth = strtoul(format, &end, 10);
  490.         format = end;
  491.         c = *format;
  492.     } else if (c == '*') {
  493.         minWidth = va_arg(args, int);
  494.         format++; 
  495.         c = *format;
  496.     }
  497.     if (c == '.') {
  498.         format++; 
  499.         c = *format;
  500.     }
  501.     if (isdigit(c)) {
  502.         precision = strtoul(format, &end, 10);
  503.         format = end;
  504.         c = *format;
  505.     } else if (c == '*') {
  506.         precision = va_arg(args, int);
  507.         format++; 
  508.         c = *format;
  509.     }
  510.     if (c == 'l') {            /* Ignored for compatibility. */
  511.         format++; 
  512.         c = *format;
  513.     }
  514.  
  515.     /*
  516.      * Take action based on the format type (which is now in c).
  517.      */
  518.  
  519.     field = buf;
  520.     switch (c) {
  521.  
  522.         case 'D':
  523.         case 'd':
  524.         i = va_arg(args, int);
  525.         if (i < 0) {
  526.             prefix = "-";
  527.             i = -i;
  528.             actualLength = 1;
  529.         }
  530.         field = CvtUtoA((unsigned) i, 10, buf, &tmp);
  531.         actualLength += tmp;
  532.         break;
  533.         
  534.         case 'O':
  535.         case 'o':
  536.         i = va_arg(args, int);
  537.         if (altForm && (i != 0)) {
  538.             prefix = "0";
  539.             actualLength = 1;
  540.         }
  541.         field = CvtUtoA((unsigned) i, 8, buf, &tmp);
  542.         actualLength += tmp;
  543.         break;
  544.         
  545.         case 'X':
  546.         case 'x':
  547.         i = va_arg(args, int);
  548.         field = CvtUtoA((unsigned) i, 16, buf, &actualLength);
  549.         if (altForm) {
  550.             char *p;
  551.             if (c == 'X') {
  552.             if (i != 0) {
  553.                 prefix = "0X";
  554.                 actualLength += 2;
  555.             }
  556.             for (p = field; *p != 0; p++) {
  557.                 if (*p >= 'a') {
  558.                 *p += 'A' - 'a';
  559.                 }
  560.             }
  561.             } else if (i != 0) {
  562.             prefix = "0x";
  563.             actualLength += 2;
  564.             }
  565.         }
  566.         break;
  567.         
  568.         case 'U':
  569.         case 'u':
  570.         field = CvtUtoA(va_arg(args, unsigned), 10, buf,
  571.             &actualLength);
  572.         break;
  573.         
  574.         case 's':
  575.         field = va_arg(args, char *);
  576.         if (field == (char *) NULL) {
  577.             field = "(NULL)";
  578.         } 
  579.         actualLength = strlen(field);
  580.         if ((precision >= 0) && (precision < actualLength)) {
  581.             actualLength = precision;
  582.         }
  583.         pad = ' ';
  584.         break;
  585.  
  586.         case 'c':
  587.         buf[0] = va_arg(args, int);
  588.         actualLength = 1;
  589.         pad = ' ';
  590.         break;
  591.  
  592.         case 'F':
  593.         case 'f':
  594.         if (precision < 0) {
  595.             precision = 6;
  596.         } else if (precision > CVT_DBL_BUF_SIZE) {
  597.             precision = CVT_DBL_BUF_SIZE;
  598.         }
  599.  
  600.         /*
  601.          * Just generate the digits and compute the total length
  602.          * here.  The rest of the work will be done when the
  603.          * characters are actually output, below.
  604.          */
  605. #ifdef sun4
  606.          /*
  607.           * Varargs is not correctly implemented in gcc version 1.34
  608.           * for the sun4.  This problem should be fixed in the next
  609.           * version of the compiler, and this code can then be
  610.           * deleted.
  611.           */
  612.          {
  613.              union {
  614.                  long i[2];
  615.                  double d;
  616.              } u;
  617.  
  618.              u.i[0] = va_arg(args, long);
  619.              u.i[1] = va_arg(args, long);
  620.  
  621.              actualLength = CvtFtoA(u.d, CVT_DBL_BUF_SIZE,
  622.              precision, &point, &sign, field, &fpError);
  623.          }
  624. #else
  625.         actualLength = CvtFtoA(va_arg(args, double), CVT_DBL_BUF_SIZE,
  626.             precision, &point, &sign, field, &fpError);
  627. #endif
  628.         if (fpError) {
  629.             break;
  630.         }
  631.         if (point <= 0) {
  632.             actualLength += 1 - point;
  633.         }
  634.         if ((precision != 0) || (altForm)) {
  635.             actualLength += 1;
  636.         }
  637.         if (sign) {
  638.             prefix = "-";
  639.             actualLength += 1;
  640.         }
  641.         c = 'f';
  642.         break;
  643.  
  644.         case 'E':
  645.         case 'e':
  646.         if (precision < 0) {
  647.             precision = 6;
  648.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  649.             precision = CVT_DBL_BUF_SIZE-1;
  650.         }
  651. #ifdef sun4
  652.          /*
  653.           * Varargs is not correctly implemented in gcc version 1.34
  654.           * for the sun4.  This problem should be fixed in the next
  655.           * version of the compiler, and this code can then be
  656.           * deleted.
  657.           */
  658.          {
  659.              union {
  660.                  long i[2];
  661.                  double d;
  662.              } u;
  663.  
  664.              u.i[0] = va_arg(args, long);
  665.              u.i[1] = va_arg(args, long);
  666.  
  667.              actualLength = CvtFtoA(u.d, precision+1, -1,
  668.              &point, &sign, &buf[1]);
  669.          }
  670. #else
  671.         actualLength = CvtFtoA(va_arg(args, double), precision+1, -1,
  672.             &point, &sign, &buf[1]);
  673. #endif
  674.         if (fpError) {
  675.             break;
  676.         }
  677.         eFromG:
  678.  
  679.         /*
  680.          * Insert a decimal point after the first digit of the number.
  681.          * If no digits after decimal point, then don't print decimal
  682.          * unless in altForm.
  683.          */
  684.  
  685.         buf[0] = buf[1];
  686.         buf[1] = '.';
  687.         if ((precision != 0) || (altForm)) {
  688.             field = buf + precision + 2;
  689.         } else {
  690.             field = &buf[1];
  691.         }
  692.  
  693.         /*
  694.          * Convert the exponent.
  695.          */
  696.         
  697.         *field = c;
  698.             field++;
  699.         point--;    /* One digit before decimal point. */
  700.         if (point < 0) {
  701.             *field = '-';
  702.             point = -point;
  703.         } else {
  704.             *field = '+';
  705.         }
  706.         field++;
  707.         if (point < 10) {
  708.             *field = '0';
  709.             field++;
  710.         }
  711.         strcpy(field, CvtUtoA((unsigned) point, 10, expBuf, &i));
  712.         actualLength = (field - buf) + i;
  713.         field = buf;
  714.         if (sign) {
  715.             prefix = "-";
  716.             actualLength += 1;
  717.         }
  718.         break;
  719.  
  720.         case 'G':
  721.         case 'g': {
  722.         int eLength, fLength;
  723.  
  724.         if (precision < 0) {
  725.             precision = 6;
  726.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  727.             precision = CVT_DBL_BUF_SIZE-1;
  728.         } else if (precision == 0) {
  729.             precision = 1;
  730.         }
  731.  
  732. #ifdef sun4
  733.          /*
  734.           * Varargs is not correctly implemented in gcc version 1.34
  735.           * for the sun4.  This problem should be fixed in the next
  736.           * version of the compiler, and this code can then be
  737.           * deleted.
  738.           */
  739.          {
  740.              union {
  741.                  long i[2];
  742.                  double d;
  743.              } u;
  744.  
  745.              u.i[0] = va_arg(args, long);
  746.              u.i[1] = va_arg(args, long);
  747.  
  748.              actualLength = CvtFtoA(u.d, precision,
  749.              -1, &point, &sign, &buf[1]);
  750.          }
  751. #else
  752.         actualLength = CvtFtoA(va_arg(args, double), precision,
  753.             -1, &point, &sign, &buf[1]);
  754.  
  755. #endif
  756.         if (fpError) {
  757.             break;
  758.         }
  759.         if (!altForm) {
  760.             for ( ; actualLength > 1; actualLength--) {
  761.             if (buf[actualLength] != '0') {
  762.                 break;
  763.             }
  764.             }
  765.         }
  766.         if ((actualLength > 1) || altForm) {
  767.             eLength = actualLength + 5;
  768.         } else {
  769.             eLength = actualLength + 4;
  770.         }
  771.         if (point <= 0) {
  772.             fLength = actualLength + 2 - point;
  773.         } else {
  774.             fLength = actualLength;
  775.             if (point < actualLength) {
  776.             fLength += 1;
  777.             } else if (altForm) {
  778.             fLength = point + 1;
  779.             } else {
  780.             fLength = point;
  781.             }
  782.         }
  783.  
  784.         /*
  785.          * Use "e" format if it results in fewer digits than "f"
  786.          * format, or if it would result in non-significant zeroes
  787.          * being printed.  Remember that precision means something
  788.          * different in "e" and "f" (digits after decimal) than it
  789.          * does in "g" (significant digits).
  790.          */
  791.  
  792.         if ((eLength < fLength) || (point > precision)) {
  793.             c += 'E' - 'G';
  794.             precision = actualLength-1;
  795.             goto eFromG;
  796.         }
  797.         c = 'f';
  798.         field = &buf[1];
  799.         actualLength = fLength;
  800.         if (sign) {
  801.             prefix = "-";
  802.             actualLength += 1;
  803.         }
  804.         break;
  805.         }
  806.  
  807.         case '%':
  808.         putc('%', stream);
  809.         charsPrinted += 1;
  810.         goto endOfField;
  811.  
  812.         case 0:
  813.         return charsPrinted;
  814.  
  815.         default:
  816.         putc(c, stream);
  817.         charsPrinted += 1;
  818.         goto endOfField;
  819.     }
  820.  
  821.     /* Handle pad characters on the left.  If the pad is '0', then
  822.      * padding goes after the prefix.  Otherwise, padding goes before
  823.      * the prefix.
  824.      */
  825.  
  826.     if (!leftAdjust) {
  827.         if (pad == '0') {
  828.         for ( ; *prefix != 0; prefix++) {
  829.             putc(*prefix, stream);
  830.             charsPrinted += 1;
  831.             actualLength--;
  832.             minWidth--;
  833.         }
  834.         }
  835.         while (minWidth > actualLength) {
  836.         putc(pad, stream);
  837.         charsPrinted += 1;
  838.         minWidth --;
  839.         }
  840.     }
  841.  
  842.     /*
  843.      * Output anything left in the prefix.
  844.      */
  845.  
  846.     minWidth -= actualLength;
  847.     for ( ; *prefix != 0; prefix++) {
  848.         putc(*prefix, stream);
  849.         charsPrinted += 1;
  850.         actualLength--;
  851.     }
  852.  
  853.     /*
  854.      * "F" and "f" formats are handled specially here:  output
  855.      * everything up to and including the decimal point.
  856.      */
  857.  
  858.     if (c == 'f' && !fpError) {
  859.         if (point <= 0) {
  860.         if (actualLength > 0) {
  861.             putc('0', stream);
  862.             charsPrinted += 1;
  863.             point++;
  864.             actualLength--;
  865.         }
  866.         if (actualLength > 0) {
  867.             charsPrinted += 1;
  868.             putc('.', stream);
  869.             actualLength--;
  870.         }
  871.         while ((point <= 0) && (actualLength > 0)) {
  872.             putc('0', stream);
  873.             charsPrinted += 1;
  874.             point++;
  875.             actualLength--;
  876.         }
  877.         } else {
  878.         while ((point > 0) && (actualLength > 0)) {
  879.             putc(*field, stream);
  880.             charsPrinted += 1;
  881.             field++;
  882.             point--;
  883.             actualLength--;
  884.         }
  885.         if (actualLength > 0) {
  886.             putc('.', stream);
  887.             charsPrinted += 1;
  888.             actualLength--;
  889.         }
  890.         }
  891.     }
  892.  
  893.     /*
  894.      * Output the contents of the field (for "f" format, this is
  895.      * just the stuff after the decimal point).
  896.      */
  897.  
  898.     charsPrinted += actualLength;
  899.     for ( ; actualLength > 0; actualLength--, field++) {
  900.         putc(*field, stream);
  901.         }
  902.  
  903.     /*
  904.      * Pad the right of the field, if necessary.
  905.      */
  906.  
  907.     while (minWidth > 0) {
  908.         putc(' ', stream);
  909.         charsPrinted += 1;
  910.         minWidth --;
  911.     }
  912.  
  913.     endOfField: continue;
  914.     }
  915.     return charsPrinted;
  916. }
  917.